package at.mensch;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

public class Table {
	private static final Logger LOG = Logger.getLogger(Table.class);
	private List<Field> fieldList = new ArrayList<Field>();
	private List<HomeField> homeFields = new ArrayList<HomeField>(16);
	private List<FinishField> finishFields = new ArrayList<FinishField>(16);
	
	private Map<Field,Pawn> fieldMap = new HashMap<Field, Pawn>(); // "Landkarte" der Zugfelder
	
	public Table(){
		
		for(int i=1;i<41;i++){
			Field f = new Field();
			f.setFieldId(i);
			f.setFieldTitle("Feld: "+(i));
			switch(i){
			case 1:
				f.setFieldImage("field1.png");
				
				break;
			case 11:
			case 21:
			case 31:
				f.setFieldImage("field"+((i/10)+1)+".png");
				break;
			default:
				f.setFieldImage("field.png");
				break;
			}
			this.fieldList.add(f);
		}
		
		for(int i=41;i<57;i++){
			
			HomeField f = new HomeField();
			f.setFieldId(i);
			f.setFieldTitle("Feld "+i+": Startfeld Spieler");
			switch(i){
			case 41:
			case 42:
			case 43:
			case 44:
				f.setPlayerId(1);
				f.setFieldImage("field1.png");
				break;
			case 45:
			case 46:
			case 47:
			case 48:
				f.setPlayerId(2);
				f.setFieldImage("field2.png");
				break;
			case 49:
			case 50:
			case 51:
			case 52:
				f.setPlayerId(3);
				f.setFieldImage("field3.png");
				break;
			case 53:
			case 54:
			case 55:
			case 56:
				f.setPlayerId(4);
				f.setFieldImage("field4.png");
				break;
			}
			this.homeFields.add(f);
		}
		
		for(int i = 57; i<73;i++){
			FinishField f = new FinishField();
			f.setFieldId(i);
			f.setFieldTitle("Feld "+i+": Zielfeld Spieler");
			switch(i){
			case 57:
			case 58:
			case 59:
			case 60:
				f.setPlayerId(1);
				f.setFieldImage("field1.png");
				break;
			case 61:
			case 62:
			case 63:
			case 64:
				f.setPlayerId(2);
				f.setFieldImage("field2.png");
				break;
			case 65:
			case 66:
			case 67:
			case 68:
				f.setPlayerId(3);
				f.setFieldImage("field3.png");
				break;
			case 69:
			case 70:
			case 71:
			case 72:
				f.setPlayerId(4);
				f.setFieldImage("field4.png");
				break;
			}
			this.finishFields.add(f);
		}
	}

	
	/**
	 * Ein gegebenes Feld wird auf vorhandene Figuren geprueft
	 * @param f - Feld das auf vorhandene Figuren pruefen soll
	 * @return true - wenn das Feld besetzt ist, false - wenn es frei ist
	 */
	public boolean checkFieldForOccupant(Field f){
		if(fieldMap.get(f) != null){
			return true;
		}
		return false;
	}
	
	public boolean checkHomeFieldForPawn(Pawn p){
		Map<HomeField, Pawn> map = p.getPlayer().getHeim();
		for(Entry<HomeField, Pawn> e : map.entrySet()){
			if(e.getValue() == p){
				return true;
			}
		}return false;
	}
	
	public List<Field> getFieldList() {
		return fieldList;
	}
	
	public Map<Field, Pawn> getFieldMap() {
		return fieldMap;
	}
	
	public List<FinishField> getFinishFields() {
		return finishFields;
	}
	
	/**
	 * Diese Methode dient dazu, um von einem gegebenen Spieler die Zielfelder zu berechnen
	 * @param player - Spieler, von welchem die Zielfelder gesetzt werden sollen
	 * @return Liste von FinishFields des gegebenen Spielers
	 */
	public List<FinishField> getFinishFieldsOfPlayer(Player player){
		List<FinishField> ff = new ArrayList<FinishField>(4);
		
		switch(player.getPlayerId()){
		case 1:
			ff.add(finishFields.get(0));
			ff.add(finishFields.get(1));
			ff.add(finishFields.get(2));
			ff.add(finishFields.get(3));
			break;
		case 2:
			ff.add(finishFields.get(4));
			ff.add(finishFields.get(5));
			ff.add(finishFields.get(6));
			ff.add(finishFields.get(7));
			break;
		case 3:
			ff.add(finishFields.get(8));
			ff.add(finishFields.get(9));
			ff.add(finishFields.get(10));
			ff.add(finishFields.get(11));
			break;
		case 4:
			ff.add(finishFields.get(12));
			ff.add(finishFields.get(13));
			ff.add(finishFields.get(14));
			ff.add(finishFields.get(15));
			break;
		}
		return ff;
	}
	
	public List<HomeField> getHomeFields() {
		return homeFields;
	}
	
	/**
	 * Analog zu getFinishFieldsOfPlayer, nur mit Startfeldern
	 * @param player - Spieler, von welchem die Startfelder berechnet werden sollen
	 * @return hf - eine Liste von HomeFields 
	 */
	public List<HomeField> getHomeFieldsOfPlayer(Player player){
		
		List<HomeField> hf = new ArrayList<HomeField>(4);
		
		switch(player.getPlayerId()){
		case 1:
			hf.add(homeFields.get(0));
			hf.add(homeFields.get(1));
			hf.add(homeFields.get(2));
			hf.add(homeFields.get(3));
			break;
		case 2:
			hf.add(homeFields.get(4));
			hf.add(homeFields.get(5));
			hf.add(homeFields.get(6));
			hf.add(homeFields.get(7));
			break;
		case 3:
			hf.add(homeFields.get(8));
			hf.add(homeFields.get(9));
			hf.add(homeFields.get(10));
			hf.add(homeFields.get(11));
			break;
		case 4:
			hf.add(homeFields.get(12));
			hf.add(homeFields.get(13));
			hf.add(homeFields.get(14));
			hf.add(homeFields.get(15));
			break;
		}
		return hf;
	}
	
	/**
	 * Gibt das letzte Feld des Spielfeldes fuer eine Figur zurueck
	 * @param pawn - Figur fuer die das letzte Feld berechnet werden soll
	 * @return Field: lastFieldOfGame - Das letzte Feld einer Figur vor dem Ziel
	 */
	public Field getLastFieldOfGame(Pawn pawn){
		Field lastFieldOfGame = new Field();

		switch(pawn.getPlayer().getPlayerId()){
		case 1:
			lastFieldOfGame = fieldList.get(41);
			break;
		case 2:
			lastFieldOfGame = fieldList.get(11);
			break;
		case 3:
			lastFieldOfGame = fieldList.get(21);
			break;
		case 4: 
			lastFieldOfGame = fieldList.get(31);
			break;
		}
		return lastFieldOfGame;
	}
	
	public Field getCurrentFieldOfPawn(Pawn pawn){
		Field currentField = new Field();
		
		for(Entry<Field, Pawn> e : fieldMap.entrySet()){
			if(e.getValue() == pawn){
				currentField = e.getKey();
			}
		}
		return currentField;
	}
	
	public Pawn getPawnOnField(Field f){
		return fieldMap.get(f);
	}
	
	/**
	 * Schaut ob ein Spieler schon figuren im feld hat
	 * Dazu wird zuerst die Liste der Figuren eines Spielers geholt
	 * Danach wird ueber die Field Map iteriert ob der aufscheint
	 * @param p - Player that should be checked
	 * @return true - wenn der Spieler schon Figuren im Feld hat, false wenn nicht
	 */
	public boolean checkFieldForPawnOfPlayer(Player p){
		Pawn pawn = new Pawn();
		for(int i = 0; i<p.getPawnList().size();i++){
			pawn = p.getPawnList().get(i);
			for(Entry<Field, Pawn> e : fieldMap.entrySet()){
				if(e.getValue() == pawn){
					return true;
				}
			}
		}
		return false;
	}
	/**
	 * Berechnet auf welches Feld die Figur nach einem Wuerfelzug landen soll.
	 * Ist die FieldId > 40, dann wird von der FieldID 40 abgezogen, da nach 40 die Felder bei 1 zu zaehlen beginnen
	 * @param pawn
	 * @param dice
	 * @return Field - das auf das nach dem Wuerfeln gezogen werden soll
	 */
	public Field getNewFieldForPawn(Pawn pawn, int dice){
		Field designatedField = new Field();
		Field currentField = getCurrentFieldOfPawn(pawn);
		
		int newFieldId = currentField.getFieldId() + dice;
		
		for(Field f : fieldList){
			if(newFieldId < 41){
				if(f.getFieldId() == newFieldId){
					designatedField = f;
				}
			}else{
				if(f.getFieldId() == (newFieldId-40)){
					designatedField = f;
				}
			}
		}
		return designatedField;
	}
	
	/**
	 * Prueft ob die Figur sich ueber das letzte seiner Spielfelder bewegt oder genau drauf steht
	 * D.h. der naechste Zug kann nur ins Ziel fueheren
	 * @return
	 */
	public boolean moveOverLastField(){
		return false;
	}
	
	/**
	 * Diese Methode setzt eine Figur ins Ziel (d.h. entfernt sie aus der fieldMap - HashMap und setzt sie in die Zielfelder Hashmap, 
	 * welche beim besitzenden Spieler als Attribut eingetragen ist)
	 * TODO: Was soll hier noch implementiert werden:
	 * 		- wenn das alteFeld + Wuerfelergebnis > fieldId des letzten Feldes, heisst das, dass die Figur ueber ihr letztes Feld ziehen wuerde
	 * 				ist das also der Fall, kann man sie ins Ziel schieben
	 * 		- aber nur dann, wenn: altesFeld + Ergebnis zusaetzlich kleiner/gleich ist als die hoechste FinishField ID 
	 * 				sonst wuerde sie ja ueber das letzte finishfield hinausziehen)
	 * 		-  
	 * @param pawn - Figur, die ins Ziel geschoben werden soll
	 */
	public void putPawnIntoFinish(Pawn pawn){

		
	}
	
	/**
	 * Setzt den gegebenen Bauern, abhaengig von seiner SpielerID, an das erste Feld des Spielfeldes
	 * Wenn das Feld besetzt ist, dann wird die Figur geworfen (Achtung: da derzeit nur jeweils eine Figur
	 * herumlaufen, wurde die Abfrage, ob es sich um eine eigene Figur handelt, nicht eingebaut!!!
	 * 
	 * 
	 * @param pawn
	 */
	public void putPawnIntoGame(Pawn pawn){
		
		Field designatedField = new Field();

		switch(pawn.getPlayer().getPlayerId()){
		case 1:
			designatedField = fieldList.get(0);
			break;
		case 2:
			designatedField = fieldList.get(10);
			break;
		case 3:
			designatedField = fieldList.get(20);
			break;
		case 4: 
			designatedField = fieldList.get(30);
			break;
		}
		
		if(checkFieldForOccupant(designatedField)){
			setPawnToHomeField(fieldMap.get(designatedField));
		}
		removePawnFromHomeField(pawn);
		putPawnOnNewField(pawn, designatedField);
	}
	
	/**
	 * Bewegt eine Figur innerhalb des Spielfeldes auf seine neue Position
	 * @param pawn - die Figur, die bewegt werden soll
	 * @param newField - das neue Feld der Figur
	 */
	public void putPawnOnNewField(Pawn pawn, Field newField){
		fieldMap.put(newField, pawn);
	}
	
	/**
	 * Der gegebene Bauer wird aus dem HomeField genommen, und nicht mehr.
	 * Wichtig hier: es wird kein remove aus der Hashmap gemacht sondern die 
	 * ehemalige position "null" gesetzt. Durch remove wuerde auch der Key geloescht
	 * und die Abfrage aus "setPawnToHomeField" ( == null) wuerde nicht mehr gehen 
	 * @param pawn
	 */
	public void removePawnFromHomeField(Pawn pawn){
		Player p = pawn.getPlayer();
		Map<HomeField, Pawn> hf = p.getHeim();
		HomeField hfToReset = null;
		for( Entry<HomeField, Pawn> entry : hf.entrySet() ){
			if(  pawn.equals( entry.getValue() ) ){
				hfToReset = entry.getKey();
			}
		}
		
		if( hfToReset != null ){
			System.out.println("Setze Nullwert auf dem Feld: " +hfToReset.getFieldId() + " Fuer Spieler "+hfToReset.getPlayerId());
			hf.put( hfToReset, null );
		}
	}
	
	/**
	 * Entfernt das alte Feld der Figur aus der Hashmap
	 * @param oldField - altes Feld der Figur
	 */
	public void removePawnFromOldField(Field oldField){
		fieldMap.remove(oldField);
	}
	
	public void setFieldList(List<Field> fieldlist) {
		this.fieldList = fieldlist;
	}

	public void setFieldMap(Map<Field, Pawn> fieldMap) {
		this.fieldMap = fieldMap;
	}

	public void setFinishFields(List<FinishField> finishFields) {
		this.finishFields = finishFields;
	}

	public void setHomeFields(List<HomeField> homeFields) {
		this.homeFields = homeFields;
	}

	/**
	 * Kann fuer jegliches hinauswerfen eines Bauern verwendet werden, um diesen an den Start zurueckzusetzen
	 * Die Methode holt sich vom Besitzer des Bauern die HomeField Hashmap und schaut, wo diese einen
	 * freien Platz aufweist. An diese Stelle wird der Bauer gesetzt
	 * @param pawn - Bauer der an den Start gesetzt werden soll
	 */
	public void setPawnToHomeField(Pawn pawn){
		Map<HomeField, Pawn> hf = pawn.getPlayer().getHeim();
		HomeField freeHomeField = null;
		
		for(Entry<HomeField, Pawn> e : hf.entrySet()){
			if(e.getValue() == null){
				freeHomeField = e.getKey();
				break;
			}
		}
		
		if(freeHomeField != null){
			hf.put( freeHomeField, pawn );
		}
	}

	/**
	 * Geht zuerst ueber die gesamte Liste der Felder (fieldList)
	 * Im switch werden, abhaengig von der FieldId, die Default Tags fuer die einzelnen Felder gesetzt
	 * Ist das abgeschlossen, wird ueber die Map fieldMap iteriert und geschaut ob ein Feld darin enthalten ist.
	 * Wenn dem so ist, dann wird der Default Tag ueberschrieben, ebenfalls abhaengig von der FieldId (==> andere Bilder fuer die jeweiligen ersten Felder) 
	 */
	public void updateFieldTags(){
		for(Field f : fieldList){
			switch(f.getFieldId()){
			case 1:
				f.setFieldTitle("Feld 1: erstes Feld Spieler 1");
				f.setFieldImage("field1.png");
				break;
			case 11:
				f.setFieldTitle("Feld 11: erstes Feld Spieler 2");
				f.setFieldImage("field2.png");
				break;
			case 21:
				f.setFieldTitle("Feld 21: erstes Feld Spieler 3");
				f.setFieldImage("field3.png");
				break;
			case 31:
				f.setFieldTitle("Feld 31: erstes Feld Spieler 4");
				f.setFieldImage("field4.png");
				break;
			case 10:
				f.setFieldTitle("Feld 10: letztes Feld Spieler 2");
				f.setFieldImage("field.png");
				break;
			case 20:
				f.setFieldTitle("Feld 20: letztes Feld Spieler 3");
				f.setFieldImage("field.png");
				break;
			case 30:
				f.setFieldTitle("Feld 30: letztes Feld Spieler 4");
				f.setFieldImage("field.png");
				break;
			case 40:
				f.setFieldTitle("Feld 40: letztes Feld Spieler 1");
				f.setFieldImage("field.png");
				break;
			default:
				f.setFieldTitle("Feld "+f.getFieldId());
				f.setFieldImage("field.png");
				break;
			}
			for(Entry<Field, Pawn> e : fieldMap.entrySet()){
				if(e.getKey() == f){
					System.out.println("Field ID: "+f.getFieldId()+" Spieler: " + e.getValue().getPlayer().getPlayerId());
					switch(f.getFieldId()){
					case 1:
						f.setFieldTitle("Feld "+f.getFieldId()+": erstes Feld Spieler 1: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field1_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 11:
						f.setFieldTitle("Feld "+f.getFieldId()+": erstes Feld Spieler 2: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field2_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 21:
						f.setFieldTitle("Feld "+f.getFieldId()+": erstes Feld Spieler 3: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field3_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 31:
						f.setFieldTitle("Feld "+f.getFieldId()+": erstes Feld Spieler 4: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field4_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 10:
						f.setFieldTitle("Feld "+f.getFieldId()+": letztes Feld Spieler 2: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 20:
						f.setFieldTitle("Feld "+f.getFieldId()+": letztes Feld Spieler 3: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 30:
						f.setFieldTitle("Feld "+f.getFieldId()+": letztes Feld Spieler 4: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					case 40:
						f.setFieldTitle("Feld "+f.getFieldId()+": letztes Feld Spieler 1: Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					default:
						f.setFieldTitle("Feld "+f.getFieldId()+": Spieler "+e.getValue().getPlayer().getPlayerId());
						f.setFieldImage("field_player"+ e.getValue().getPlayer().getPlayerId()+".png");
						break;
					}
				}
			}
		}
	}
	
	/**
	 * Analog zu updateHomeFieldTags, nur nicht mit dem Typ HomeField, sondern mit dem Typ FinishField
	 * @param players
	 */
	public void updateFinishFieldTags(List<Player> players){
		for(FinishField ff : finishFields){
			ff.setFieldTitle("Feld "+ff.getFieldId()+": Zielfeld Spieler "+ff.getPlayerId());
			ff.setFieldImage("field"+ff.getPlayerId()+".png");
			for(int i=0;i<players.size();i++){
				for(Entry<FinishField, Pawn> e : players.get(i).getZiel().entrySet()){
					if(e.getValue() != null){
						if(e.getKey() == ff){
							ff.setFieldTitle("Feld "+ff.getFieldId()+": Zielfeld Spieler "+e.getValue().getPlayer().getPlayerId()+": Spieler "+e.getValue().getPlayer().getPlayerId());
							ff.setFieldImage("field"+e.getValue().getPlayer().getPlayerId()+"_player"+e.getValue().getPlayer().getPlayerId()+".png");
						}
					}
				}
			}
		}
	}

	/**
	 * Aktualisiert die img, alt und title Tags aller Heimfelder
	 * @param Liste mit den Spielern des Spiels: players
	 */
	public void updateHomeFieldTags(List<Player> players){
		LOG.debug("Player List size: " + players.size());
		Pawn lookForMe = null;
		Player checkMe = null;
		HomeField modifyMe = null;
		
		for(int i = 0; i < players.size(); i++){
			LOG.debug("Durchlauf: " + i);
			
			LOG.debug("Checke Figuren des Spielers: " + players.get(i).getPlayerId());
			checkMe = players.get(i);
			for(int x = 0; x < players.get(i).getPawnList().size();x++){
				lookForMe = players.get(i).getPawnList().get(x);
				for(Entry<HomeField, Pawn> e : checkMe.getHeim().entrySet()){
					if(e.getValue() == lookForMe){
						LOG.debug("Bauer "+ lookForMe.getPawnId() + " wurde in der Hashmap an der Position " + e.getKey().getFieldId() + " gefunden");
						modifyMe = e.getKey();
						modifyMe.setFieldTitle("Feld "+modifyMe.getFieldId()+": Startfeld Spieler " + checkMe.getPlayerId()+": Spieler "+checkMe.getPlayerId());
						modifyMe.setFieldImage("field"+checkMe.getPlayerId()+"_player"+checkMe.getPlayerId()+".png");
						LOG.debug("Title Tags von Feld " + modifyMe.getFieldId() + "wurden mit einem Spieler besetzt");
						LOG.debug("********************************");
					}if(e.getValue() == null){
						LOG.debug("Es wurde KEIN "+ lookForMe.getPawnId() + " in der Hashmap an der Position " + e.getKey().getFieldId() + " gefunden");
						modifyMe = e.getKey();
						modifyMe.setFieldTitle("Feld "+modifyMe.getFieldId()+": Startfeld Spieler "+checkMe.getPlayerId());
						modifyMe.setFieldImage("field"+checkMe.getPlayerId()+".png");
						LOG.debug("Daher wurden die Tags auf default gesetzt: Field ID: " + modifyMe.getFieldId());
						LOG.debug("++++++++++++++++++++++++++++++++++++++++++++++++++");
					}
					
				}
			}
			LOG.debug("---------------------------");
		}	
	}
}
